﻿#include "ssTransform.h"
#include "../node/ssNode.h"
#include "../3dMath/ss3dMathFunction.h"


namespace StarSeeker
{

ssTransform::ssTransform()
	:m_vZoom(1,1,1), m_vRotate(0,0,0,1), m_vMove(0,0,0), m_transformFlag(0), m_transformDirty(false)
{
	m_type = SS_COMPONENT_TRANSFORM;
	m_matView[0].Identity();
	m_matView[1].Identity();
}

ssTransform::~ssTransform()
{
}

ssTransform* ssTransform::Parent()
{
	if (m_pNode && m_pNode->Parent())
	{
		ssComponent* ce = m_pNode->Parent()->GetComponent(SS_COMPONENT_TRANSFORM);
		if (ce)
		{
			return SS_DYNAMIC_CAST(ssTransform*, ce);
		}
	}
	return 0;
}

ssTransform* ssTransform::FindChild(const char* name)
{
	if (m_pNode)
	{
		ssNode* c = m_pNode->FindChild(name);
		if (c)
		{
			ssComponent* ce = c->GetComponent(SS_COMPONENT_TRANSFORM);
			if (ce)
			{
				return SS_DYNAMIC_CAST(ssTransform*, ce);
			}
		}
	}
	return 0;
}

ssTransform* ssTransform::FindChild(u32 offset)
{
	if (m_pNode)
	{
		ssNode* c = m_pNode->FindChild(offset);
		if (c)
		{
			ssComponent* ce = c->GetComponent(SS_COMPONENT_TRANSFORM);
			if (ce)
			{
				return SS_DYNAMIC_CAST(ssTransform*, ce);
			}
		}
	}
	return 0;
}

void ssTransform::SetPosition(ssfloat x, ssfloat y, ssfloat z)
{
	m_vMove.x = x;
	m_vMove.y = y;
	m_vMove.z = z;
	m_transformFlag |= SS_TF_MOVE;
	m_transformDirty = true;
	//ComputeViewMatrix();
	//UpdateChildren();
}

void ssTransform::SetPosition(const ssFLOAT3X & v)
{
	SetPosition(v.x, v.y, v.z);
}

ssFLOAT3X ssTransform::GetPosition()
{
	return m_vMove;
}

void ssTransform::SetRotation(const ssFLOAT4X& qt)
{
	m_vRotate = qt;
	m_transformFlag |= SS_TF_ROTATE;
	m_transformDirty = true;
	//ComputeViewMatrix();
	//UpdateChildren();
}

ssFLOAT4X ssTransform::GetRotation()
{
	return m_vRotate;
}

void ssTransform::SetScaling(ssfloat x, ssfloat y, ssfloat z)
{
	m_vZoom.x = x;
	m_vZoom.y = y;
	m_vZoom.z = z;
	m_transformFlag |= SS_TF_ZOOM;
	m_transformDirty = true;
	//ComputeViewMatrix();
	//UpdateChildren();
}

void ssTransform::SetScaling(const ssFLOAT3X & v)
{
	SetScaling(v.x, v.y, v.z);
}

ssFLOAT3X ssTransform::GetScaling()
{
	return m_vZoom;
}

StarSeeker::ssFLOAT3X ssTransform::Up()
{
	ssFLOAT3X ret(2.0f*m_vRotate.x*m_vRotate.y + 2.0f*m_vRotate.z*m_vRotate.w, 1.0f - 2.0f*m_vRotate.x*m_vRotate.x - 2.0f*m_vRotate.z*m_vRotate.z, 2.0f*m_vRotate.y*m_vRotate.z - 2.0f*m_vRotate.x*m_vRotate.w);
	return ret;
}

StarSeeker::ssFLOAT3X ssTransform::Left()
{
	ssFLOAT3X ret(1.0f - 2.0f*m_vRotate.y*m_vRotate.y - 2.0f*m_vRotate.z*m_vRotate.z, 2.0f*m_vRotate.x*m_vRotate.y - 2.0f*m_vRotate.z*m_vRotate.w, 2.0f*m_vRotate.x*m_vRotate.z + 2.0f*m_vRotate.y*m_vRotate.w);
	return ret;
}

StarSeeker::ssFLOAT3X ssTransform::Forward()
{
	ssFLOAT3X ret(2.0f*m_vRotate.x*m_vRotate.z - 2.0f*m_vRotate.y*m_vRotate.w, 2.0f*m_vRotate.y*m_vRotate.z + 2.0f*m_vRotate.x*m_vRotate.w, 1.0f - 2.0f*m_vRotate.x*m_vRotate.x - 2.0f*m_vRotate.y*m_vRotate.y);
	return ret;
}

StarSeeker::ssFLOAT4x4X& ssTransform::ViewMatrix(bool isGlobal/*=true*/)
{
	return isGlobal?m_matView[1]:m_matView[0];
}

void ssTransform::UpdateGlobalMatrix()
{
	ssTransform* pParent = Parent();
	if (pParent)
	{
		m_matView[1] = pParent->m_matView[1] * m_matView[0];
	}
	else
	{
		m_matView[1] = m_matView[0];
	}
}

bool ssTransform::HasFlag(u8 f)
{
	return m_transformFlag&f;
}

bool ssTransform::hasDirty()
{
	return m_transformDirty;
}

void ssTransform::ComputeViewMatrix()
{
	ssFLOAT3x3X m_matTF;
	m_matTF.Identity();
	if (m_transformFlag&SS_TF_ZOOM)
	{
		m_matTF._11 = m_vZoom.x;
		m_matTF._22 = m_vZoom.y;
		m_matTF._33 = m_vZoom.z;
	}
	if (m_transformFlag&SS_TF_ROTATE)
	{
		ssFLOAT3x3X mr;
		Math3D::QuaternionToMatrix3x3(&m_vRotate, &mr);
		m_matTF *= mr;
	}
	m_matView[0].CopyFrom3x3(m_matTF);
	if (m_transformFlag&SS_TF_MOVE)
	{
		m_matView[0]._41 = m_vMove.x;
		m_matView[0]._42 = m_vMove.y;
		m_matView[0]._43 = m_vMove.z;
	}

	UpdateGlobalMatrix();

	m_transformDirty = false;
}

void ssTransform::UpdateChildren()
{
	if (m_pNode)
	{
		ssList<ssNode*>& children = m_pNode->GetChildren();
		ssList<ssNode*>::Iterator itr = children.Begin();
		while (itr.IsVaild())
		{
			ssTransform* tf = SS_DYNAMIC_CAST(ssTransform*, (*itr)->GetComponent(SS_COMPONENT_TRANSFORM));
			if (tf)
			{
				if (!tf->hasDirty())//有变化的节点一定会重新计算，没有变化的节点由于父节点有变化需要重新计算世界矩阵
				{
					tf->m_matView[1] = m_matView[1] * tf->m_matView[0];
					tf->UpdateChildren();
				}
			}
			++itr;
		}
	}
}

}
